import { Scene, Render, Circle, Text, PickContrls, Vector2 } from '../two/two.js'
import { Mouse } from './object.js'


class Key {
    constructor(domElement) {
        if (domElement === undefined) console.warn('PickContrls: The parameter "domElement" is now mandatory.');
        if (domElement === document) console.error('PickContrls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.');
        this.domElement = domElement;
        this.isPress = false;
        this.keyCode = ''
        this.key = ''
        this.shiftKey = false
        this.ctrlKey = false
        this.altKey = false
        this.metaKey = false
        this.keypress = {}

        const scope = this
        // scope.domElement.addEventListener('keydown', onKeyDown);
        document.addEventListener("keydown" , function (event) {
            if (scope.enabled === false) return;

            scope.keyCode = event.keyCode ? event.keyCode : ''
            scope.key = event.key ? event.key : ''
            scope.keypress[event.key] = true
            scope.shiftKey = event.shiftKey
            scope.ctrlKey = event.ctrlKey
            scope.altKey = event.altKey
            scope.metaKey = event.metaKey

            for(let key in scope.keypress) {
                if (scope.keypress[key]) {
                    scope.isPress = scope.keypress[key]
                    break
                }
            }
        })

        document.addEventListener("keyup", function (event) {
            if (scope.enabled === false) return;
            scope.keyCode = ''
            scope.key = ''
            scope.keypress[event.key] = false
            scope.shiftKey = false
            scope.ctrlKey = false
            scope.altKey = false
            scope.metaKey = false

            for(let key in scope.keypress) {
                scope.isPress = scope.keypress[key]
                if (scope.keypress[key]) {
                    break
                }
            }
        })
    }
}


let render, ctx, _callback, mouse, key

function animation(callback) {
    if (typeof callback == 'function') {
        _callback = callback
    }
    if (typeof _callback == 'function') {
        // ctx.clearRect(0, 0, render._width * render._pixelRatio, render._height * render._pixelRatio)
        background()
        _callback()
    }
}

function noloop() {
    _callback = null
}

function background(color) {
    if (color) {
        ctx.fillStyle = color
        ctx.rect(0, 0, render._width * render._pixelRatio, render._height * render._pixelRatio)
        ctx.fill()
    } else {
        ctx.clearRect(0, 0, render._width * render._pixelRatio, render._height * render._pixelRatio)
    }
}

function createCanvas(width = 400, height = 300) {
    render = new Render()
    render.setSize(width, height)
    render.setPixelRatio(2)
    // render.setTickLength(1000 / 10)
    render.setAnimationLoop(animation)
    document.querySelector('body').appendChild(render.domElement)
    ctx = render._context

    mouse = new Mouse(render.domElement)
    mouse.setPixelRatio(2)

    key = new Key(render.domElement)
    return render
}

function frame(kframe) {
    render.setTickLength(1000 / kframe)
}

function fill(style='rgb(255, 255, 204)') {
    if (style) ctx.fillStyle = style
    ctx.fill()
}

function stroke(style='rgb(255, 255, 204)') {
    if (style) ctx.strokeStyle = style
    // if (lineWidth) ctx.lineWidth = lineWidth
    ctx.stroke()
}

function lineWidth(width) {
    if (width !== undefined) {
        ctx.lineWidth = width
    }
}

function draw(x, y, points=[], close=true) {
    if (!render) {
        console.error("not createCanvas before")
        return
    }
    if (!points || points.length <= 0) {
        console.error("empty points")
        return
    }
    ctx.beginPath()
    let vector = Vector2.add(vector2(x, y), points[0])
    ctx.moveTo(vector.x, vector.y)
    for (let j = 1, jl = points.length; j < jl; j++) {
        vector = Vector2.add(vector2(x, y), points[j])
        ctx.lineTo(vector.x, vector.y)
    }
    if (close) {
        vector = Vector2.add(vector2(x, y), points[0])
        ctx.lineTo(vector.x, vector.y)
    }

}

function curve(vertices=[], callback=fill) {
    if (vertices.length <= 0) return
    ctx.beginPath()
    ctx.moveTo(vertices[0].x, vertices[0].y)

    if (vertices.length >= 3) {
        for (let i = 1; i < vertices.length - 2; ++i) {
            let ctrlPoint = {
                x: (vertices[i].x + vertices[i + 1].x) / 2,
                y: (vertices[i].y + vertices[i + 1].y) / 2
            }
            ctx.quadraticCurveTo(vertices[i].x, vertices[i].y, ctrlPoint.x, ctrlPoint.y)
            // ctx.bezierCurveTo(vertices[i-1].x, vertices[i-1].y, vertices[i].x, vertices[i].y, vertices[i + 1].x, vertices[i + 1].y)
        }
        ctx.quadraticCurveTo(vertices[vertices.length - 2].x, vertices[vertices.length - 2].y, vertices[vertices.length - 1].x, vertices[vertices.length - 1].y)
    } else if (vertices.length >= 2) {
        // ctx.lineTo(vertices[1].x, vertices[1].y)
    }
    callback()
}

/*
*根据已知点获取第i个控制点的坐标
*param ps	已知曲线将经过的坐标点
*param i	第i个坐标点
*param a,b	可以自定义的正数
*/
function getCtrlPoint(ps, i, a = 0.25, b = 0.25){
	//处理两种极端情形
    let pA = {x: ps[i].x, y: ps[i].y}
    let pB = {x: ps[i].x, y: ps[i].y}
	if(i > ps.length-3){
		let last=ps.length-1
		pA.x = ps[last].x - (ps[last].x-ps[last-1].x)*a;
		pA.y = ps[last].y - (ps[last].y-ps[last-1].y)*a;
		pB.x = ps[last].x - (ps[last].x-ps[last-1].x)*b;
		pB.y = ps[last].y - (ps[last].y-ps[last-1].y)*b;
	}else{
		pA.x = ps[i].x - (ps[i+1].x-ps[i-1].x)*a;
		pA.y = ps[i].y - (ps[i+1].y-ps[i-1].y)*a;
		pB.x = ps[i+1].x - (ps[i+2].x-ps[i].x)*b;
		pB.y = ps[i+1].y - (ps[i+2].y-ps[i].y)*b;
	}
	return {
		pA:{x:pA.x,y:pA.y},
		pB:{x:pB.x,y:pB.y}
	}
}

function circle(x, y, radius=10, segments = 18, thetaStart = 0, thetaLength = Math.PI * 2) {
    let vertices = []
    for (let s = segments; s >= 0; --s) {
        const segment = thetaStart + s / segments * thetaLength;
        // vertex
        const vertex = new Vector2();
        vertex.x = radius * Math.cos(segment);
        vertex.y = radius * Math.sin(segment);

        vertices.push(vertex);
    }
    draw(x, y, vertices)
}

function rect(x, y, width = 1, height = 1, widthSegments = 1, heightSegments = 1) {
    let vertices = []
    const segment_width = width / widthSegments;
    const segment_height = height / heightSegments;

    const width_half = width / 2;
    const height_half = height / 2;

    for (let ix = 0; ix < widthSegments; ix++) {
        const x = ix * segment_width - width_half
        vertices.push(new Vector2(x, height_half))
    }
    for (let iy = 0; iy < heightSegments; iy++) {
        const y = iy * segment_height - height_half;
        vertices.push(new Vector2(width_half, -y))
    }
    for (let ix = 0; ix < widthSegments; ix++) {
        const x = ix * segment_width - width_half
        vertices.push(new Vector2(-x, -height_half))
    }

    for (let iy = 0; iy < heightSegments; iy++) {
        const y = iy * segment_height - height_half;
        vertices.push(new Vector2(-width_half, y))
    }
    draw(x, y, vertices)
}

function line(x1, y1, x2, y2) {
    if (x1 instanceof Vector2 && y1 instanceof Vector2) {
        draw(x1.x, x1.y, [vector2(0, 0), vector2(y1.x - x1.x, y1.y - x1.y)])
    } else {
        draw(x1, y1, [vector2(0, 0), vector2(x2 - x1, y2 - y1)])
    }
}

function map(n, start1, stop1, start2, stop2, withinBounds) {
  const newval = (n - start1) / (stop1 - start1) * (stop2 - start2) + start2;
  if (!withinBounds) {
    return newval;
  }
  if (start2 < stop2) {
    return Math.max(Math.min(newval, start2), stop2)
  } else {
    return Math.max(Math.min(newval, stop2), start2)
  }
}

function vector2(x = 0, y = 0) {
    return new Vector2(x, y)
}

function vector28Angle(angle) {
    return Vector2.setAngle(angle)
}

function vector2random() {
    return Vector2.random()
}

function constrain(n, low, high) {
    return Math.max(Math.min(n, high), low)
}

function random(min, max) {
    let rand = Math.random()
    if (typeof min === 'undefined') {
        return rand;
    } else if (typeof max === 'undefined') {
        if (min instanceof Array) {
            return min[Math.floor(rand * min.length)];
        } else {
            return rand * min;
        }
    } else {
        if (min > max) {
            const tmp = min;
            min = max;
            max = tmp;
        }

        return rand * (max - min) + min;
    }
}

function radians(angle) {
    return angle * Math.PI / 180
}


export { createCanvas, fill, stroke, circle, rect, line, lineWidth, curve, frame, animation, mouse, key, vector2, vector28Angle, vector2random, map, constrain, random, radians, noloop, background }